package Scenes
{
	import Config.GameConfig;
	
	import Controls.DragProxy;
	import Controls.Panel;
	
	import Input.GameInput;
	
	import Native.INativeObject;
	import Native.NativeField;
	import Native.NativeSprite;
	
	import Objects.GameObject;
	import Objects.GameTextField;
	
	import Particles.Particle;
	import Particles.ParticleEmitter;
	import Particles.ParticleLayer;
	
	import Plugin.ClickPlugin;
	import Plugin.GamePlugin;
	import Plugin.ItemClickPlugin;
	import Plugin.TogglePlugin;
	
	import Setup.ZOrder;
	
	import Tools.ArrayTool;
	import Tools.DisplayTool;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.ui.Mouse;
	import flash.ui.MouseCursor;
	import flash.utils.Dictionary;

    public class GameScene
	{
        public static var gs:GameScene;
		
		public var toSyncRemoved:Boolean=false;
        protected var ticks:int = 0;
        public var mHit:Boolean;
		public var mMove:Boolean;
        public var m:Sprite;
        private var zOrders:Array;
		public var objects:Array;
		private var emitters:Dictionary;
		private var plugins:Array;
		public var toSyncPlugins:Boolean=false;
		public var cacheOvers:Array;
		public var draging:Boolean=false;
		public var existPanel:Boolean=false;
		
        public function GameScene()
		{
            objects = new Array();
            zOrders = new Array();
			emitters=new Dictionary();
			cacheOvers=new Array();
			plugins=new Array();
            super();
            m = new Sprite();
            new ZOrder().SetupZOrder(this);
			gs=this;
        }
        public final function register(gameMain:Sprite):void
		{
			gameMain.addChildAt(m, 0);
			
            for each ( var zOrder:SceneZOrder in zOrders)
			{
                m.addChild(zOrder.m);
            }
			
            _register(gameMain);
			
			onScreenResize();
        }
		protected function _register(gameMain:Sprite):void
		{
			
		}
        public final function update():void
		{
			ticks++;
            mHit=GameInput.i.mHit;
			mMove=GameInput.i.mMove;
			mouseCheck();
			_update();
            for each (var go:GameObject in objects) 
			{
				if(go.intelligent)
				{
					go.update();
				}
				if(go.toSyncRemoved)
				{
					go.syncRemoved();
					go.toSyncRemoved=false;
				}
            }
			for each(var plugin:GamePlugin in plugins)
			{
				plugin.update();
			}
			if(toSyncPlugins)
			{
				syncPlugins();
				toSyncPlugins=false;
			}
			if(toSyncRemoved)
			{
				syncRemoved();
				toSyncRemoved=false;
			}
			statistical();
			for each (var zo:SceneZOrder in zOrders)
			{
				zo.pl.update();
			}
			resetFlags();
        }
        protected function _update():void
		{
			
        }
		private function syncRemoved():void
		{
			objects = objects.filter(function (go:GameObject, index:int, arr:Array):Boolean{
				return !go.removed;
			});
		}
		private function syncPlugins():void
		{
			plugins = plugins.filter(function (plugin:GamePlugin, index:int, arr:Array):Boolean{
				return !plugin.removed;
			});
		}
		private function statistical():void
		{
			resetStatistical();
			for each(var go:GameObject in objects)
			{
				if(go.statistical)
				{
					analyzeStatistical(go);
				}
			}
		}
		private function resetStatistical():void
		{
			existPanel=false;
			draging=false;
			_resetStatistical();
		}
		protected function _resetStatistical():void
		{
			
		}
		private function analyzeStatistical(go:GameObject):void
		{
			if(go is DragProxy)
			{
				draging=true;
			}
			if(go is Panel)
			{
				existPanel=true;
			}
			_analyzeStatistical(go);
		}
		protected function _analyzeStatistical(go:GameObject):void
		{
			
		}
        public function getZOrder(name:String):SceneZOrder
		{
            var zOrder:SceneZOrder;
            for each (zOrder in zOrders) 
			{
                if (zOrder.name == name)
				{
                    return zOrder;
                }
            }
            return null;
        }
        public function addZOrder(name:String):void
		{
            var zOrder:SceneZOrder = new SceneZOrder();
			zOrder.name = name;
			zOrder.m = new Sprite();
			zOrder.pl = new ParticleLayer();
			zOrder.pl.parent = zOrder.m;
            zOrders.push(zOrder);
        }
        public function findObjectByClass(cls:Class):GameObject
		{
            for each (var go:GameObject in objects) 
			{
                if (go is cls)
				{
                    return go;
                }
            }
            return null;
        }
		public function particleKilledCallback(particle:Particle):void
		{
			
		}
		public function addGameObject(go:GameObject,zOrderString:String):void
		{
			if(go.intelligent)
			{
				go.update();
			}
			var zOrder:SceneZOrder=getZOrder(zOrderString);
			zOrder.m.addChild(go.obj);
		}
		public function addEmitter(emitter:ParticleEmitter):void
		{
			emitters[emitter.name]=emitter;
		}
		public function getEmitter(emitter:ParticleEmitter):ParticleEmitter
		{
			return emitters[emitter.name];
		}
		public function addItemClick(objects:Array,handler:Function):void
		{
			var plugin:ItemClickPlugin=new ItemClickPlugin();
			plugin.objects=objects;
			plugin.clickHandler=handler;
			addPlugin(plugin);
		}
		public function addToggle(objects:Array,handler:Function=null):TogglePlugin
		{
			var plugin:TogglePlugin=new TogglePlugin();
			plugin.objects=objects;
			plugin.changeCallBack=handler;
			addPlugin(plugin);
			return plugin;
		}
		public function addClick(go:GameObject,handler:Function):void
		{
			var plugin:ClickPlugin=new ClickPlugin();
			plugin.go=go;
			plugin.clickHandler=handler;
			addPlugin(plugin);
		}
		public function emitOnto(zOrderString:String,emitterName:String,x:Number,y:Number,appendFunc:Function=null):void
		{
			var zOrder:SceneZOrder=getZOrder(zOrderString);
			var emitter:ParticleEmitter=emitters[emitterName];
			if(emitter)
			{
				emitter.emitOnto(zOrder.pl,x,y,appendFunc);
			}
		}
		public function addPlugin(plugin:GamePlugin):void
		{
			plugin.gs=this;
			plugins.push(plugin);
			plugin.update();
		}
		protected function resetFlags():void
		{
			
		}
		public function mouseCheck():void
		{
			var disp:DisplayObject;
			var dispList:Array;
			var checkObject:DisplayObject;
			dispList=m.getObjectsUnderPoint(new Point(GameInput.i.mousex,GameInput.i.mousey));
			var index:int=dispList.length-1;
			while(index>=0)
			{
				disp=dispList[index];
				var blockMouse:Boolean=DisplayTool.blockMouse(disp,m);
				if(blockMouse)
				{
					checkObject=disp;
					break;
				}
				index--;
			}
			var go:GameObject;
			for each(go in cacheOvers)
			{
				go.overed=false;
			}
			var list:Array=ArrayTool.clone(cacheOvers);
			cacheOvers.splice(0);
			var cursor:String=MouseCursor.AUTO;
			if(checkObject)
			{
				dispList=DisplayTool.getObjDisplayList(checkObject,m);
				for each(disp in dispList)
				{
					if(disp is INativeObject)
					{
						go=INativeObject(disp).go;
						go.overed=true;
						cacheOvers.push(go);
						
						if(go.mOver)
						{
							if(go.toolTipData)
							{
								go.createToolTip();
							}
							if(go.buttonCursor)
							{
								cursor=MouseCursor.BUTTON;
							}
							if(go.canDrag&&go.mDown)
							{
								go.createDragProxy();
							}
							if(go.activeOver)
							{
								go.doActiveOver();
							}
						}
					}
				}
			}
			
			for each(go in list)
			{
				if(go.activeOver)
				{
					if(!go.mOver)
					{
						go.unActiveOver();
					}
				}
			}
			
			Mouse.cursor=cursor;
		}
		public final function onScreenResize():void
		{
			for each(var go:GameObject in objects)
			{
				go.onScreenResize();
			}
			_onScreenResize();
		}
		protected function _onScreenResize():void
		{
			
		}
		public function destroy():void
		{
			for each(var go:GameObject in objects)
			{
				if(!go.parent)
				{
					go.remove();
				}
			}
			objects = new Array();
			emitters=new Dictionary();
			for each(var plugin:GamePlugin in plugins)
			{
				plugin.remove();
			}
			plugins=new Array();
			for each(var zOrder:SceneZOrder in zOrders)
			{
				zOrder.pl.remove();
			}
			zOrders=new Array();
			if(m.parent)
			{
				m.parent.removeChild(m);
			}
		}
    }
}